package com.kuangjia.student_ems.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.kuangjia.student_ems.dto.LeaveDTO;
import com.kuangjia.student_ems.dto.request.LeaveRequest;
import com.kuangjia.student_ems.entity.Leave;
import com.kuangjia.student_ems.entity.User;
import com.kuangjia.student_ems.exception.ResourceNotFoundException;
import com.kuangjia.student_ems.repository.LeaveRepository;
import com.kuangjia.student_ems.repository.UserRepository;
import com.kuangjia.student_ems.repository.LeaveMapper;
import com.kuangjia.student_ems.service.LeaveService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class LeaveServiceImpl implements LeaveService {

    private static final Logger logger = LoggerFactory.getLogger(LeaveServiceImpl.class);
    
    private final LeaveRepository leaveRepository;
    private final UserRepository userRepository;
    private final LeaveMapper leaveMapper;
    
    @Autowired
    public LeaveServiceImpl(LeaveRepository leaveRepository, UserRepository userRepository, LeaveMapper leaveMapper) {
        this.leaveRepository = leaveRepository;
        this.userRepository = userRepository;
        this.leaveMapper = leaveMapper;
    }
    
    @Override
    @Transactional
    public LeaveDTO createLeave(Long userId, LeaveRequest request) {
        try {
            User user = userRepository.findById(userId)
                    .orElseThrow(() -> new ResourceNotFoundException("用户", "id", userId));
            
            // 检查日期范围是否合理
            if (request.getEndTime().isBefore(request.getStartTime())) {
                throw new IllegalArgumentException("请假结束时间不能早于开始时间");
            }
            
            // 检查是否与已有请假时间重叠
            List<Leave> overlappingLeaves = leaveRepository.findUserLeavesDuringPeriod(userId, request.getStartTime(), request.getEndTime());
            if (!overlappingLeaves.isEmpty()) {
                throw new IllegalArgumentException("请假时间与已有请假记录重叠");
            }
            
            Leave leave = new Leave();
            leave.setUser(user);
            leave.setType(request.getType());
            leave.setStartTime(request.getStartTime());
            leave.setEndTime(request.getEndTime());
            leave.setReason(request.getReason());
            leave.setStatus(Leave.LeaveStatus.PENDING);
            
            Leave savedLeave = leaveRepository.save(leave);
            return convertToDTO(savedLeave);
        } catch (Exception e) {
            logger.error("创建请假记录时发生异常，用户ID: {}, 请假类型: {}", userId, request.getType(), e);
            throw e;
        }
    }
    
    @Override
    @Transactional
    public LeaveDTO updateLeave(Long leaveId, LeaveRequest request) {
        Leave leave = leaveRepository.findById(leaveId)
                .orElseThrow(() -> new ResourceNotFoundException("请假记录", "id", leaveId));
        
        // 只有待审批状态的请假记录才能修改
        if (leave.getStatus() != Leave.LeaveStatus.PENDING) {
            throw new IllegalStateException("只有待审批状态的请假记录才能修改");
        }
        
        // 检查日期范围是否合理
        if (request.getEndTime().isBefore(request.getStartTime())) {
            throw new IllegalArgumentException("请假结束时间不能早于开始时间");
        }
        
        // 检查是否与已有请假时间重叠（排除当前记录）
        List<Leave> overlappingLeaves = leaveRepository.findUserLeavesDuringPeriod(leave.getUser().getId(), request.getStartTime(), request.getEndTime());
        overlappingLeaves.removeIf(l -> l.getId().equals(leaveId));
        if (!overlappingLeaves.isEmpty()) {
            throw new IllegalArgumentException("请假时间与已有请假记录重叠");
        }
        
        leave.setType(request.getType());
        leave.setStartTime(request.getStartTime());
        leave.setEndTime(request.getEndTime());
        leave.setReason(request.getReason());
        
        Leave updatedLeave = leaveRepository.save(leave);
        return convertToDTO(updatedLeave);
    }
    
    @Override
    @Transactional
    public void deleteLeave(Long leaveId) {
        Leave leave = leaveRepository.findById(leaveId)
                .orElseThrow(() -> new ResourceNotFoundException("请假记录", "id", leaveId));
        
        // 移除状态检查限制，允许删除所有状态的请假记录
        // if (leave.getStatus() != Leave.LeaveStatus.PENDING) {
        //     throw new IllegalStateException("只有待审批状态的请假记录才能删除");
        // }
        
        leaveRepository.deleteById(leaveId);
    }
    
    @Override
    public LeaveDTO getLeaveById(Long leaveId) {
        try {
            Leave leave = leaveRepository.findById(leaveId)
                    .orElseThrow(() -> new ResourceNotFoundException("请假记录", "id", leaveId));
            return convertToDTO(leave);
        } catch (Exception e) {
            logger.error("根据ID获取请假记录时发生异常，请假ID: {}", leaveId, e);
            throw e;
        }
    }
    
    @Override
    public List<LeaveDTO> getLeavesByUser(Long userId) {
        if (!userRepository.existsById(userId)) {
            throw new ResourceNotFoundException("用户", "id", userId);
        }
        List<Leave> leaves = leaveRepository.findByUserIdOrderByCreateTimeDesc(userId);
        return leaves.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }
    
    @Override
    public List<LeaveDTO> getLeavesByUserAndStatus(Long userId, Leave.LeaveStatus status) {
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new ResourceNotFoundException("用户", "id", userId));
        List<Leave> leaves = leaveRepository.findByUserAndStatusOrderByCreateTimeDesc(user, status);
        return leaves.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }
    
    @Override
    public List<LeaveDTO> getLeavesByDepartment(Long departmentId) {
        List<Leave> leaves = leaveRepository.findByDepartment(departmentId);
        return leaves.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }
    
    @Override
    public List<LeaveDTO> getPendingLeavesByDepartment(Long departmentId) {
        List<Leave> leaves = leaveRepository.findPendingLeavesByDepartmentId(departmentId);
        return leaves.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }
    
    @Override
    public List<LeaveDTO> getLeavesByDepartmentAndStatus(Long departmentId, Leave.LeaveStatus status) {
        List<Leave> leaves = leaveRepository.findByDepartmentAndStatus(departmentId, status);
        return leaves.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }
    
    @Override
    public List<LeaveDTO> getLeavesDuringPeriod(LocalDateTime startTime, LocalDateTime endTime) {
        List<Leave> leaves = leaveRepository.findLeavesDuringPeriod(startTime, endTime);
        return leaves.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }
    
    @Override
    public List<LeaveDTO> getUserLeavesDuringPeriod(Long userId, LocalDateTime startTime, LocalDateTime endTime) {
        if (!userRepository.existsById(userId)) {
            throw new ResourceNotFoundException("用户", "id", userId);
        }
        List<Leave> leaves = leaveRepository.findUserLeavesDuringPeriod(userId, startTime, endTime);
        return leaves.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }
    
    @Override
    @Transactional
    public LeaveDTO approveLeave(Long leaveId, Long approverId, String approveReason) {
        try {
            Leave leave = leaveRepository.findById(leaveId)
                    .orElseThrow(() -> new ResourceNotFoundException("请假记录", "id", leaveId));
            
            User approver = userRepository.findById(approverId)
                    .orElseThrow(() -> new ResourceNotFoundException("审批人", "id", approverId));
            
            // 检查请假记录状态
            if (leave.getStatus() != Leave.LeaveStatus.PENDING) {
                throw new IllegalStateException("只有待审批状态的请假记录才能审批");
            }
            
            // 检查审批权限
            if (approver.getRole() == User.UserRole.EMPLOYEE) {
                throw new IllegalStateException("普通员工无权审批请假申请");
            }
            
            // 部门经理只能审批本部门员工的请假
            if (approver.getRole() == User.UserRole.DEPARTMENT_MANAGER 
                    && !approver.getDepartment().getId().equals(leave.getUser().getDepartment().getId())) {
                throw new IllegalStateException("部门经理只能审批本部门员工的请假申请");
            }
            
            leave.setStatus(Leave.LeaveStatus.APPROVED);
            leave.setApproveReason(approveReason);
            leave.setApprover(approver);
            leave.setApproveTime(LocalDateTime.now());
            
            Leave updatedLeave = leaveRepository.save(leave);
            return convertToDTO(updatedLeave);
        } catch (Exception e) {
            logger.error("审批请假时发生异常，请假ID: {}, 审批人ID: {}, 批准意见: {}", leaveId, approverId, approveReason, e);
            throw e;
        }
    }
    
    @Override
    @Transactional
    public LeaveDTO rejectLeave(Long leaveId, Long approverId, String rejectReason) {
        Leave leave = leaveRepository.findById(leaveId)
                .orElseThrow(() -> new ResourceNotFoundException("请假记录", "id", leaveId));
        
        User approver = userRepository.findById(approverId)
                .orElseThrow(() -> new ResourceNotFoundException("审批人", "id", approverId));
        
        // 检查请假记录状态
        if (leave.getStatus() != Leave.LeaveStatus.PENDING) {
            throw new IllegalStateException("只有待审批状态的请假记录才能审批");
        }
        
        // 检查审批权限
        if (approver.getRole() == User.UserRole.EMPLOYEE) {
            throw new IllegalStateException("普通员工无权审批请假申请");
        }
        
        // 部门经理只能审批本部门员工的请假
        if (approver.getRole() == User.UserRole.DEPARTMENT_MANAGER 
                && !approver.getDepartment().getId().equals(leave.getUser().getDepartment().getId())) {
            throw new IllegalStateException("部门经理只能审批本部门员工的请假申请");
        }
        
        leave.setStatus(Leave.LeaveStatus.REJECTED);
        leave.setRejectReason(rejectReason);
        leave.setApprover(approver);
        leave.setApproveTime(LocalDateTime.now());
        
        Leave updatedLeave = leaveRepository.save(leave);
        return convertToDTO(updatedLeave);
    }
    
    @Override
    @Transactional
    public LeaveDTO cancelLeave(Long leaveId) {
        Leave leave = leaveRepository.findById(leaveId)
                .orElseThrow(() -> new ResourceNotFoundException("请假记录", "id", leaveId));
        
        // 只有待审批或已批准但未开始的请假才能取消
        if (leave.getStatus() != Leave.LeaveStatus.PENDING 
                && (leave.getStatus() != Leave.LeaveStatus.APPROVED || leave.getStartTime().isBefore(LocalDateTime.now()))) {
            throw new IllegalStateException("只有待审批或已批准但未开始的请假才能取消");
        }
        
        leave.setStatus(Leave.LeaveStatus.CANCELLED);
        
        Leave updatedLeave = leaveRepository.save(leave);
        return convertToDTO(updatedLeave);
    }
    
    @Override
    public List<LeaveDTO> getAllLeaves() {
        List<Leave> leaves = leaveRepository.findAllByOrderByCreateTimeDesc();
        return leaves.stream().map(this::convertToDTO).collect(java.util.stream.Collectors.toList());
    }
    
    @Override
    public List<LeaveDTO> searchLeaves(String keyword) {
        if (keyword == null || keyword.trim().isEmpty()) {
            return getAllLeaves();
        }
        
        String searchTerm = "%" + keyword.toLowerCase() + "%";
        List<Leave> leaves = leaveRepository.searchLeaves(searchTerm);
        return leaves.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }
    
    @Override
    public IPage<LeaveDTO> getLeavePage(Page<Leave> page, String keyword, Long userId, String sortField, String sortOrder) {
        try {
            QueryWrapper<Leave> wrapper = new QueryWrapper<>();
            if (keyword != null && !keyword.isEmpty()) {
                wrapper.lambda().like(Leave::getReason, keyword);
            }
            if (userId != null) {
                wrapper.lambda().eq(Leave::getUserId, userId);
            }
            // 排序 - 默认按创建时间降序（最新的在前）
            if (sortField != null && !sortField.isEmpty()) {
                boolean isAsc = "asc".equalsIgnoreCase(sortOrder);
                switch (sortField.toLowerCase()) {
                    case "starttime":
                        wrapper.lambda().orderBy(true, isAsc, Leave::getStartTime);
                        break;
                    case "endtime":
                        wrapper.lambda().orderBy(true, isAsc, Leave::getEndTime);
                        break;
                    case "createtime":
                        wrapper.lambda().orderBy(true, isAsc, Leave::getCreateTime);
                        break;
                    case "updatetime":
                        wrapper.lambda().orderBy(true, isAsc, Leave::getUpdateTime);
                        break;
                    case "approvetime":
                        wrapper.lambda().orderBy(true, isAsc, Leave::getApproveTime);
                        break;
                    default:
                        // 默认按创建时间降序，最新的请假记录显示在前面
                        wrapper.lambda().orderByDesc(Leave::getCreateTime);
                        break;
                }
            } else {
                // 默认按创建时间降序，最新的请假记录显示在前面
                wrapper.lambda().orderByDesc(Leave::getCreateTime);
            }
            IPage<Leave> leavePage = leaveMapper.selectPage(page, wrapper);
            return leavePage.convert(this::convertToDTO);
        } catch (Exception e) {
            logger.error("分页查询请假记录时发生异常，页码: {}, 页大小: {}, 关键词: {}, 用户ID: {}", 
                page.getCurrent(), page.getSize(), keyword, userId, e);
            throw e;
        }
    }
    
    private LeaveDTO convertToDTO(Leave leave) {
        try {
            LeaveDTO dto = new LeaveDTO();
            dto.setId(leave.getId());
            
            // 处理用户信息 - 如果user对象为null，则通过userId查询
            if (leave.getUser() != null) {
                dto.setUserId(leave.getUser().getId());
                dto.setUserName(leave.getUser().getName());
                
                if (leave.getUser().getDepartment() != null) {
                    dto.setDepartmentId(leave.getUser().getDepartment().getId());
                    dto.setDepartmentName(leave.getUser().getDepartment().getName());
                }
            } else if (leave.getUserId() != null) {
                // 如果user对象为null但有userId，则查询用户信息
                try {
                    User user = userRepository.findById(leave.getUserId()).orElse(null);
                    if (user != null) {
                        dto.setUserId(user.getId());
                        dto.setUserName(user.getName());
                        
                        if (user.getDepartment() != null) {
                            dto.setDepartmentId(user.getDepartment().getId());
                            dto.setDepartmentName(user.getDepartment().getName());
                        }
                    } else {
                        dto.setUserId(leave.getUserId());
                        dto.setUserName("未知用户");
                    }
                } catch (Exception e) {
                    logger.warn("查询用户信息失败，用户ID: {}", leave.getUserId(), e);
                    dto.setUserId(leave.getUserId());
                    dto.setUserName("未知用户");
                }
            } else {
                dto.setUserId(null);
                dto.setUserName("未知用户");
            }
            
            dto.setType(leave.getType());
            dto.setTypeDesc(getLeaveTypeDesc(leave.getType()));
            dto.setStartTime(leave.getStartTime());
            dto.setEndTime(leave.getEndTime());
            dto.setReason(leave.getReason());
            dto.setStatus(leave.getStatus());
            dto.setStatusDesc(getLeaveStatusDesc(leave.getStatus()));
            dto.setRejectReason(leave.getRejectReason());
            dto.setApproveReason(leave.getApproveReason());
            
            // 处理审批人信息
            if (leave.getApprover() != null) {
                dto.setApproverId(leave.getApprover().getId());
                dto.setApproverName(leave.getApprover().getName());
            } else if (leave.getApproverId() != null) {
                try {
                    User approver = userRepository.findById(leave.getApproverId()).orElse(null);
                    if (approver != null) {
                        dto.setApproverId(approver.getId());
                        dto.setApproverName(approver.getName());
                    } else {
                        dto.setApproverId(leave.getApproverId());
                        dto.setApproverName("未知审批人");
                    }
                } catch (Exception e) {
                    logger.warn("查询审批人信息失败，审批人ID: {}", leave.getApproverId(), e);
                    dto.setApproverId(leave.getApproverId());
                    dto.setApproverName("未知审批人");
                }
            }
            
            dto.setApproveTime(leave.getApproveTime());
            dto.setCreateTime(leave.getCreateTime());
            dto.setUpdateTime(leave.getUpdateTime());
            
            return dto;
        } catch (Exception e) {
            logger.error("转换请假DTO时发生异常，请假ID: {}", leave.getId(), e);
            throw e;
        }
    }
    
    private String getLeaveTypeDesc(Leave.LeaveType type) {
        if (type == null) return "";
        
        switch (type) {
            case ANNUAL: return "年假";
            case SICK: return "病假";
            case PERSONAL: return "事假";
            case MARRIAGE: return "婚假";
            case MATERNITY: return "产假";
            case PATERNITY: return "陪产假";
            case BEREAVEMENT: return "丧假";
            case OTHER: return "其他";
            default: return "";
        }
    }
    
    private String getLeaveStatusDesc(Leave.LeaveStatus status) {
        if (status == null) return "";
        
        switch (status) {
            case PENDING: return "待审批";
            case APPROVED: return "已批准";
            case REJECTED: return "已拒绝";
            case CANCELLED: return "已取消";
            default: return "";
        }
    }
} 